package cn.org.xiaosheng.controller;



import cn.org.xiaosheng.listener.CacheWarmer;
import cn.org.xiaosheng.service.CacheService;
import com.github.benmanes.caffeine.cache.AsyncCache;
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
import com.google.common.cache.Cache;
import com.google.common.cache.LoadingCache;
import lombok.RequiredArgsConstructor;
import net.sf.ehcache.Element;
import net.sf.ehcache.statistics.StatisticsGateway;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

@RestController
@RequestMapping("/cache")
@RequiredArgsConstructor
public class CacheController {

    private final CacheService testCache;
    // 小伙伴们可以自行debug，看看此时是使用了哪一个manager（当没有配置manager时）
    @Autowired
    private final CacheManager cacheManager;

    @Resource
    private CacheService cacheService;

    @Autowired
    private LoadingCache<String, String> loadingCache;

    @Autowired
    private Cache<String, String> cache;

    @Autowired
    private com.github.benmanes.caffeine.cache.Cache<String, String> caffeineCache;

    @Autowired
    private com.github.benmanes.caffeine.cache.LoadingCache<String, String> loadingCaffeineCache;

    @Autowired
    private AsyncLoadingCache asyncLoadingCache;

    @Autowired
    private AsyncCache asyncCache;

    @Resource(name = "userCache")
    private net.sf.ehcache.Cache userCache;

    @GetMapping("/getBrownCache")
    public String getBrownCache() {
        System.out.println("进入了getBrownCache请求代码中");
        return "Brown Cache";
    }

    @GetMapping("/getSpringCache")
    public String getSpringCache() {
        System.out.println("进入了getSpringCache请求代码中");
        return "Spring Cache";
    }

    @GetMapping("/{id}")
    public String testCacheById(@PathVariable("id") String id){
        return testCache.getCacheById(id);
    }

    @GetMapping("testFind/{id}")
    public String testFindCacheById(@PathVariable("id") String id){
        return testCache.findCacheById(id);
    }

    @DeleteMapping("/{id}")
    public String testDeleteCacheById(@PathVariable("id") String id){
        testCache.deleteCacheById(id);
        SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
        return "okk";
    }

    @PutMapping("/{id}")
    public String testUpdateCacheById(@PathVariable("id") String id){
        return testCache.updateCacheById(id);
    }

    @GetMapping("/GuavaCache/{key}")
    public String getGuavaCache(@PathVariable("key") String key) throws ExecutionException {
        // 方便自定义每次的获取逻辑， 原理跟CacheLoader.load()一致。 如果缓存中不存在，则调用callable()来进行获取放入缓存中。
        String s = cache.get(key, new Callable<String>() {
            @Override //回调方法用于读源并写入缓存
            public String call() throws Exception {
                // 缓存不存在则查询数据库
                String dataFromDatabase = cacheService.getDataFromDatabase(key);
                // 写回缓存
                loadingCache.put(key, dataFromDatabase);
                // 显示写回缓存, 当key存在时不进行操作，key不存在时进行插入操作
//                loadingCache.asMap().putIfAbsent(key, dataFromDatabase);
                return dataFromDatabase;
            }
        });
        //打印输出统计
        System.out.println(cache.stats().toString()+", " + cache.stats().hitRate());
        return s;
    }

    @PostMapping("/GuavaCache/{key}")
    public String getGuavaLoadingCache(@PathVariable("key") String key) throws ExecutionException {
        // 直接去缓存中取用，若不存在会根据配置的数据获取方法进行获取
        String s = loadingCache.get(key);
        //打印输出统计
        System.out.println(loadingCache.stats().toString()+", " + loadingCache.stats().hitRate());
        return s;
    }

    @DeleteMapping("/GuavaCache/{key}")
    public String testDeleteLoadingCache(@PathVariable("key") String key){
        cache.invalidate(key);
        return "success!";
    }

    @GetMapping("/CaffeineCache/{key}")
    public String getCaffeineCache(@PathVariable("key") String key){
        String s = caffeineCache.get(key,k -> cacheService.getDataFromDatabase(k));
        return s;
    }

    @PostMapping("/CaffeineCache/{key}")
    public String getCaffeineLoadingCache(@PathVariable("key") String key){
        return loadingCaffeineCache.get(key);
    }

    @GetMapping("/CaffeineCacheManager/{key}")
    public String getCaffeineCacheManager(@PathVariable("key") String key){
//        cacheManager.getCache("caffeine").get(key,k -> cacheService.getDataFromDatabase(k));
        String s = cacheManager.getCache("caffeine").get(key, new Callable<String>() {
            @Override //回调方法用于读源并写入缓存
            public String call() throws Exception {
                // 缓存不存在则查询数据库
                String dataFromDatabase = cacheService.getDataFromDatabase(key);
                // 写回缓存
                loadingCache.put(key, dataFromDatabase);
                // 显示写回缓存, 当key存在时不进行操作，key不存在时进行插入操作
//                loadingCache.asMap().putIfAbsent(key, dataFromDatabase);
                return dataFromDatabase;
            }
        });
        return s;
    }

    @PostMapping("/CaffeineCacheManager/{key}")
    public String postCaffeineCacheManager(@PathVariable("key") String key){
//        cacheManager.getCache("caffeine").get(key,k -> cacheService.getDataFromDatabase(k));
        String s = cacheService.getCacheById(key);
        return s;
    }

    @GetMapping("/Ehcache/{key}")
    public String getEhcacheCache(@PathVariable("key") String key){
        if (userCache.isKeyInCache(key)) {
            return Objects.toString(userCache.get(key).getObjectValue());
        }
        Element element = new Element(key, cacheService.getCacheById(key));
        userCache.put(element);
        return Objects.toString(userCache.get(key).getObjectValue());
    }

    @DeleteMapping("/Ehcache/{key}")
    public String deleteEhcacheCache(@PathVariable("key") String key){
        if (userCache.isKeyInCache(key)) {
            userCache.remove(key);
            return "移除成功!";
        }
        return "元素不存在";
    }

    @PostMapping("/Ehcache/Statistics/{key}")
    public String postEhcacheCache(@PathVariable("key") String key){
        // 获取缓存的统计信息
        StatisticsGateway stats = userCache.getStatistics();
        System.out.println("缓存命中次数: " + stats.cacheHitCount());
        System.out.println("缓存错过次数: " + stats.cacheMissExpiredCount());
        return "success!";
    }

    /**
     * 通过监听器实现缓存预热
     * @return
     */
    @GetMapping("/cacheListener")
    public String getCacheListener() {
        return CacheWarmer.cacheMap.get("xiaosheng");
    }
}
